<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>精确调整的圆环弹性碰撞模拟</title>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            line-height: 1.6;
            color: #333;
            background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
            min-height: 100vh;
            padding: 20px;
        }
        .container {
            max-width: 1400px;
            margin: 0 auto;
            display: grid;
            grid-template-columns: 1fr 400px;
            gap: 20px;
        }
        header {
            grid-column: 1 / -1;
            text-align: center;
            margin-bottom: 20px;
            padding: 20px;
            background: rgba(255, 255, 255, 0.8);
            border-radius: 10px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }
        h1 {
            color: #2c3e50;
            margin-bottom: 10px;
        }
        .description {
            color: #7f8c8d;
            max-width: 800px;
            margin: 0 auto;
        }
        .simulation-area {
            background: white;
            border-radius: 10px;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
            overflow: hidden;
            display: flex;
            flex-direction: column;
            position: relative;
        }
        .canvas-container {
            flex: 1;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
        }
        canvas {
            background: #fff;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
        }
        .controls-panel {
            background: white;
            border-radius: 10px;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
            padding: 20px;
            display: flex;
            flex-direction: column;
            gap: 15px;
            max-height: 800px;
            overflow-y: auto;
        }
        .control-group {
            background: #f8f9fa;
            padding: 15px;
            border-radius: 8px;
            border-left: 4px solid #3498db;
        }
        .control-group h3 {
            margin-bottom: 10px;
            color: #2c3e50;
            font-size: 1.1rem;
        }
        .slider-container {
            display: flex;
            flex-direction: column;
            gap: 8px;
            margin-bottom: 10px;
        }
        .slider-container label {
            display: flex;
            justify-content: space-between;
        }
        .slider-value {
            font-weight: bold;
            color: #3498db;
        }
        input[type="range"] {
            width: 100%;
            height: 8px;
            border-radius: 4px;
            background: #dfe6e9;
            outline: none;
        }
        .button-group {
            display: flex;
            gap: 10px;
            flex-wrap: wrap;
        }
        button {
            padding: 10px 15px;
            border: none;
            border-radius: 5px;
            background: #3498db;
            color: white;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s ease;
            flex: 1;
            min-width: 120px;
        }
        button:hover {
            background: #2980b9;
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }
        button:active {
            transform: translateY(0);
        }
        button.reset {
            background: #e74c3c;
        }
        button.reset:hover {
            background: #c0392b;
        }
        button.start {
            background: #2ecc71;
        }
        button.start:hover {
            background: #27ae60;
        }
        .stats {
            background: #2c3e50;
            color: white;
            padding: 15px;
            border-radius: 8px;
            margin-top: 10px;
        }
        .stats h3 {
            margin-bottom: 10px;
            text-align: center;
        }
        .stat-item {
            display: flex;
            justify-content: space-between;
            margin-bottom: 5px;
        }
        .color-indicator {
            display: inline-block;
            width: 12px;
            height: 12px;
            border-radius: 50%;
            margin-right: 5px;
        }
        .ball-controls {
            display: none;
        }
        .ball-controls.active {
            display: block;
        }
        .ball-selector {
            display: flex;
            flex-wrap: wrap;
            gap: 5px;
            margin-bottom: 15px;
        }
        .ball-option {
            padding: 8px 12px;
            background: #ecf0f1;
            border-radius: 4px;
            cursor: pointer;
            transition: all 0.2s;
            text-align: center;
            flex: 1;
            min-width: 60px;
        }
        .ball-option.active {
            background: #3498db;
            color: white;
            font-weight: bold;
        }
        .coordinate-controls {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 10px;
        }
        .victory-message {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: rgba(0, 0, 0, 0.8);
            color: white;
            padding: 20px 40px;
            border-radius: 10px;
            text-align: center;
            font-size: 24px;
            font-weight: bold;
            z-index: 100;
            display: none;
            animation: victoryPulse 2s infinite;
        }
        @keyframes victoryPulse {
            0% { transform: translate(-50%, -50%) scale(1); }
            50% { transform: translate(-50%, -50%) scale(1.1); }
            100% { transform: translate(-50%, -50%) scale(1); }
        }
        @media (max-width: 1100px) {
            .container {
                grid-template-columns: 1fr;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>精确调整的圆环弹性碰撞模拟</h1>
            <p class="description">可以独立调整每个小球的位置和方向，没有线条的小球会消失，最后剩下的小球获胜！</p>
        </header>
        
        <div class="simulation-area">
            <div class="canvas-container">
                <canvas id="simulationCanvas" width="700" height="500"></canvas>
                <div id="victoryMessage" class="victory-message"></div>
            </div>
        </div>
        
        <div class="controls-panel">
            <div class="control-group">
                <h3>小球设置</h3>
                <div class="slider-container">
                    <label>
                        小球数量: <span id="ballCountValue" class="slider-value">4</span>
                    </label>
                    <input type="range" id="ballCount" min="2" max="8" value="4">
                </div>
                <div class="slider-container">
                    <label>
                        小球速度: <span id="ballSpeedValue" class="slider-value">2.0</span>
                    </label>
                    <input type="range" id="ballSpeed" min="0.5" max="5" step="0.1" value="2">
                </div>
                <div class="slider-container">
                    <label>
                        小球半径: <span id="ballRadiusValue" class="slider-value">8</span>
                    </label>
                    <input type="range" id="ballRadius" min="5" max="15" value="8">
                </div>
            </div>
            
            <div class="control-group">
                <h3>小球选择</h3>
                <div class="ball-selector" id="ballSelector">
                    <!-- 小球选项将动态生成 -->
                </div>
            </div>
            
            <div id="ballControlsContainer">
                <!-- 小球控制面板将动态生成 -->
            </div>
            
            <div class="control-group">
                <h3>全局控制</h3>
                <div class="button-group">
                    <button id="positionEven">等分分布</button>
                    <button id="positionRandom">随机分布</button>
                    <button id="positionCircle">圆形分布</button>
                </div>
                <div class="button-group">
                    <button id="directionRandom">随机方向</button>
                    <button id="directionCenter">指向中心</button>
                    <button id="directionTangent">切线方向</button>
                </div>
            </div>
            
            <div class="control-group">
                <h3>模拟控制</h3>
                <div class="button-group">
                    <button id="startBtn" class="start">开始模拟</button>
                    <button id="pauseBtn">暂停</button>
                    <button id="resetBtn" class="reset">重置模拟</button>
                </div>
            </div>
            
            <div class="stats">
                <h3>统计信息</h3>
                <div class="stat-item">
                    <span>运行时间:</span>
                    <span id="timeValue">0.0s</span>
                </div>
                <div class="stat-item">
                    <span>剩余小球:</span>
                    <span id="remainingBallsValue">4</span>
                </div>
                <div class="stat-item">
                    <span>圆环碰撞:</span>
                    <span id="ringCollisionValue">0</span>
                </div>
                <div class="stat-item">
                    <span>小球碰撞:</span>
                    <span id="ballCollisionValue">0</span>
                </div>
                <div class="stat-item">
                    <span>活跃线段数:</span>
                    <span id="segmentValue">0</span>
                </div>
            </div>
        </div>
    </div>

    <script>
        // 获取画布和上下文
        const canvas = document.getElementById('simulationCanvas');
        const ctx = canvas.getContext('2d');
        const victoryMessage = document.getElementById('victoryMessage');
        
        // 模拟参数
        const centerX = canvas.width / 2;
        const centerY = canvas.height / 2;
        const ringRadius = 200;
        
        // 控制元素
        const ballCountSlider = document.getElementById('ballCount');
        const ballCountValue = document.getElementById('ballCountValue');
        const ballSpeedSlider = document.getElementById('ballSpeed');
        const ballSpeedValue = document.getElementById('ballSpeedValue');
        const ballRadiusSlider = document.getElementById('ballRadius');
        const ballRadiusValue = document.getElementById('ballRadiusValue');
        const startBtn = document.getElementById('startBtn');
        const pauseBtn = document.getElementById('pauseBtn');
        const resetBtn = document.getElementById('resetBtn');
        const positionEvenBtn = document.getElementById('positionEven');
        const positionRandomBtn = document.getElementById('positionRandom');
        const positionCircleBtn = document.getElementById('positionCircle');
        const directionRandomBtn = document.getElementById('directionRandom');
        const directionCenterBtn = document.getElementById('directionCenter');
        const directionTangentBtn = document.getElementById('directionTangent');
        const ballSelector = document.getElementById('ballSelector');
        const ballControlsContainer = document.getElementById('ballControlsContainer');
        
        // 统计元素
        const timeValue = document.getElementById('timeValue');
        const remainingBallsValue = document.getElementById('remainingBallsValue');
        const ringCollisionValue = document.getElementById('ringCollisionValue');
        const ballCollisionValue = document.getElementById('ballCollisionValue');
        const segmentValue = document.getElementById('segmentValue');
        
        // 小球颜色
        const ballColors = [
            '#FF5252', '#4CAF50', '#2196F3', '#FFC107',
            '#9C27B0', '#FF9800', '#00BCD4', '#8BC34A'
        ];
        
        // 模拟状态
        let balls = [];
        let activeBalls = [];
        let animationId = null;
        let isRunning = false;
        let startTime = 0;
        let currentTime = 0;
        let ringCollisions = 0;
        let ballCollisions = 0;
        let collisionEffects = [];
        let gameOver = false;
        let selectedBallIndex = 0;
        
        // 小球类
        class Ball {
            constructor(x, y, angle, speed, radius, color, id) {
                this.id = id;
                this.x = x;
                this.y = y;
                this.vx = Math.cos(angle) * speed;
                this.vy = Math.sin(angle) * speed;
                this.radius = radius;
                this.color = color;
                this.collisionPoints = [];
                this.activeSegments = [];
                this.ringCollisionCount = 0;
                this.ballCollisionCount = 0;
                this.isActive = true;
                this.hasCollidedWithRing = false; // 标记是否与圆环碰撞过
                this.initialAngle = angle;
                this.initialSpeed = speed;
            }
            
            // 更新小球位置
            update() {
                if (!this.isActive) return;
                
                this.x += this.vx;
                this.y += this.vy;
                
                // 检测与圆环的碰撞
                const distanceFromCenter = Math.sqrt(
                    Math.pow(this.x - centerX, 2) + Math.pow(this.y - centerY, 2)
                );
                
                if (distanceFromCenter + this.radius > ringRadius) {
                    // 计算碰撞点
                    const angle = Math.atan2(this.y - centerY, this.x - centerX);
                    const collisionX = centerX + ringRadius * Math.cos(angle);
                    const collisionY = centerY + ringRadius * Math.sin(angle);
                    
                    // 记录碰撞点
                    this.collisionPoints.push({x: collisionX, y: collisionY});
                    this.ringCollisionCount++;
                    ringCollisions++;
                    this.hasCollidedWithRing = true;
                    
                    // 创建新线段
                    this.activeSegments.push({
                        startX: collisionX,
                        startY: collisionY,
                        endX: this.x,
                        endY: this.y,
                        active: true
                    });
                    
                    // 弹性碰撞 - 反射速度向量
                    const normalX = (this.x - centerX) / distanceFromCenter;
                    const normalY = (this.y - centerY) / distanceFromCenter;
                    
                    const dotProduct = this.vx * normalX + this.vy * normalY;
                    
                    this.vx = this.vx - 2 * dotProduct * normalX;
                    this.vy = this.vy - 2 * dotProduct * normalY;
                    
                    // 调整位置，避免卡在边界
                    const correction = distanceFromCenter + this.radius - ringRadius;
                    this.x -= correction * normalX;
                    this.y -= correction * normalY;
                }
                
                // 更新线段端点（跟随小球）
                for (let segment of this.activeSegments) {
                    if (segment.active) {
                        segment.endX = this.x;
                        segment.endY = this.y;
                    }
                }
                
                // 检查小球是否应该消失（没有活跃线段且曾经碰撞过）
                if (this.hasCollidedWithRing) {
                    let hasActiveSegment = false;
                    for (let segment of this.activeSegments) {
                        if (segment.active) {
                            hasActiveSegment = true;
                            break;
                        }
                    }
                    
                    if (!hasActiveSegment) {
                        this.isActive = false;
                    }
                }
            }
            
            // 绘制小球和其线段
            draw() {
                if (!this.isActive) return;
                
                // 绘制线段
                for (let segment of this.activeSegments) {
                    if (segment.active) {
                        ctx.beginPath();
                        ctx.moveTo(segment.startX, segment.startY);
                        ctx.lineTo(segment.endX, segment.endY);
                        ctx.strokeStyle = this.color;
                        ctx.lineWidth = 1;
                        ctx.stroke();
                    }
                }
                
                // 绘制小球
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
                ctx.fillStyle = this.color;
                ctx.fill();
                ctx.strokeStyle = '#000';
                ctx.lineWidth = 1;
                ctx.stroke();
                
                // 如果小球被选中，绘制选中效果
                if (this.id === selectedBallIndex) {
                    ctx.beginPath();
                    ctx.arc(this.x, this.y, this.radius + 5, 0, Math.PI * 2);
                    ctx.strokeStyle = '#000';
                    ctx.lineWidth = 2;
                    ctx.stroke();
                    
                    // 绘制方向指示器
                    const directionLength = 20;
                    ctx.beginPath();
                    ctx.moveTo(this.x, this.y);
                    ctx.lineTo(
                        this.x + Math.cos(this.initialAngle) * directionLength,
                        this.y + Math.sin(this.initialAngle) * directionLength
                    );
                    ctx.strokeStyle = '#000';
                    ctx.lineWidth = 2;
                    ctx.stroke();
                }
            }
            
            // 检测是否穿过其他球的线段
            checkSegmentCrossing(otherBalls) {
                if (!this.isActive) return;
                
                for (let otherBall of otherBalls) {
                    if (otherBall === this || !otherBall.isActive) continue;
                    
                    for (let i = 0; i < otherBall.activeSegments.length; i++) {
                        const segment = otherBall.activeSegments[i];
                        if (!segment.active) continue;
                        
                        // 简单的线段交叉检测
                        const prevX = this.x - this.vx;
                        const prevY = this.y - this.vy;
                        
                        if (this.isLineSegmentCrossed(prevX, prevY, this.x, this.y, 
                            segment.startX, segment.startY, segment.endX, segment.endY)) {
                            segment.active = false;
                        }
                    }
                }
            }
            
            // 线段交叉检测算法
            isLineSegmentCrossed(x1, y1, x2, y2, x3, y3, x4, y4) {
                // 计算分母
                const denominator = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1));
                
                // 如果分母为0，则线段平行
                if (denominator === 0) return false;
                
                // 计算交点参数
                const ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator;
                const ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator;
                
                // 如果交点在线段上，则返回true
                return ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1;
            }
            
            // 设置位置（极坐标）
            setPositionByPolar(radius, angle) {
                this.x = centerX + radius * Math.cos(angle);
                this.y = centerY + radius * Math.sin(angle);
            }
            
            // 设置方向
            setDirection(angle) {
                this.initialAngle = angle;
                const speed = Math.sqrt(this.vx * this.vx + this.vy * this.vy);
                this.vx = Math.cos(angle) * speed;
                this.vy = Math.sin(angle) * speed;
            }
        }
        
        // 检测和处理小球之间的碰撞
        function handleBallCollisions() {
            for (let i = 0; i < balls.length; i++) {
                const ball1 = balls[i];
                if (!ball1.isActive) continue;
                
                for (let j = i + 1; j < balls.length; j++) {
                    const ball2 = balls[j];
                    if (!ball2.isActive) continue;
                    
                    // 计算两球之间的距离
                    const dx = ball2.x - ball1.x;
                    const dy = ball2.y - ball1.y;
                    const distance = Math.sqrt(dx * dx + dy * dy);
                    
                    // 如果两球重叠，则发生碰撞
                    if (distance < ball1.radius + ball2.radius) {
                        // 计算碰撞法线
                        const nx = dx / distance;
                        const ny = dy / distance;
                        
                        // 计算相对速度
                        const dvx = ball2.vx - ball1.vx;
                        const dvy = ball2.vy - ball1.vy;
                        
                        // 计算相对速度在法线方向的分量
                        const speed = dvx * nx + dvy * ny;
                        
                        // 如果小球正在分离，则不处理碰撞
                        if (speed > 0) continue;
                        
                        // 弹性碰撞公式
                        const impulse = 2 * speed / (1 + 1); // 质量都为1
                        
                        // 更新速度
                        ball1.vx += impulse * nx;
                        ball1.vy += impulse * ny;
                        ball2.vx -= impulse * nx;
                        ball2.vy -= impulse * ny;
                        
                        // 增加碰撞计数
                        ball1.ballCollisionCount++;
                        ball2.ballCollisionCount++;
                        ballCollisions++;
                        
                        // 添加碰撞效果
                        const collisionX = (ball1.x + ball2.x) / 2;
                        const collisionY = (ball1.y + ball2.y) / 2;
                        collisionEffects.push({
                            x: collisionX,
                            y: collisionY,
                            color: '#FFFFFF',
                            startTime: Date.now()
                        });
                        
                        // 分离小球，防止卡在一起
                        const overlap = (ball1.radius + ball2.radius - distance) / 2;
                        ball1.x -= overlap * nx;
                        ball1.y -= overlap * ny;
                        ball2.x += overlap * nx;
                        ball2.y += overlap * ny;
                    }
                }
            }
        }
        
        // 绘制碰撞效果
        function drawCollisionEffects() {
            const now = Date.now();
            for (let i = collisionEffects.length - 1; i >= 0; i--) {
                const effect = collisionEffects[i];
                const elapsed = now - effect.startTime;
                const progress = elapsed / 500; // 效果持续500ms
                
                if (progress > 1) {
                    collisionEffects.splice(i, 1);
                    continue;
                }
                
                const radius = 15 * progress;
                const alpha = 0.7 * (1 - progress);
                
                ctx.beginPath();
                ctx.arc(effect.x, effect.y, radius, 0, Math.PI * 2);
                ctx.fillStyle = `rgba(255, 255, 255, ${alpha})`;
                ctx.fill();
            }
        }
        
        // 检查胜利条件
        function checkVictory() {
            if (gameOver) return;
            
            let activeBalls = balls.filter(ball => ball.isActive);
            if (activeBalls.length === 1) {
                gameOver = true;
                const winner = activeBalls[0];
                victoryMessage.textContent = `胜利者：小球 ${winner.id + 1}`;
                victoryMessage.style.display = 'block';
                victoryMessage.style.backgroundColor = winner.color;
                
                // 停止模拟
                pauseSimulation();
            } else if (activeBalls.length === 0) {
                gameOver = true;
                victoryMessage.textContent = '平局！所有小球都消失了';
                victoryMessage.style.display = 'block';
                victoryMessage.style.backgroundColor = '#2c3e50';
                
                // 停止模拟
                pauseSimulation();
            }
        }
        
        // 创建小球控制面板
        function createBallControls() {
            ballControlsContainer.innerHTML = '';
            ballSelector.innerHTML = '';
            
            const ballCount = parseInt(ballCountSlider.value);
            
            for (let i = 0; i < ballCount; i++) {
                // 创建小球选择器
                const ballOption = document.createElement('div');
                ballOption.className = `ball-option ${i === selectedBallIndex ? 'active' : ''}`;
                ballOption.innerHTML = `<span class="color-indicator" style="background-color: ${ballColors[i % ballColors.length]}"></span>小球 ${i+1}`;
                ballOption.dataset.index = i;
                ballOption.addEventListener('click', function() {
                    selectedBallIndex = parseInt(this.dataset.index);
                    updateBallSelector();
                    updateBallControls();
                });
                ballSelector.appendChild(ballOption);
                
                // 创建小球控制面板
                const ballControl = document.createElement('div');
                ballControl.className = `ball-controls ${i === selectedBallIndex ? 'active' : ''}`;
                ballControl.id = `ballControl-${i}`;
                ballControl.innerHTML = `
                    <h3>小球 ${i+1} 控制</h3>
                    <div class="slider-container">
                        <label>
                            位置半径: <span id="ballRadiusValue-${i}" class="slider-value">0</span>
                        </label>
                        <input type="range" id="ballPositionRadius-${i}" min="0" max="${ringRadius - 20}" value="0">
                    </div>
                    <div class="slider-container">
                        <label>
                            位置角度: <span id="ballAngleValue-${i}" class="slider-value">0°</span>
                        </label>
                        <input type="range" id="ballPositionAngle-${i}" min="0" max="360" value="0">
                    </div>
                    <div class="slider-container">
                        <label>
                            方向角度: <span id="ballDirectionValue-${i}" class="slider-value">0°</span>
                        </label>
                        <input type="range" id="ballDirection-${i}" min="0" max="360" value="0">
                    </div>
                    <div class="button-group">
                        <button class="apply-ball-position" data-index="${i}">应用位置</button>
                        <button class="apply-ball-direction" data-index="${i}">应用方向</button>
                    </div>
                `;
                ballControlsContainer.appendChild(ballControl);
                
                // 添加事件监听
                const positionRadiusSlider = document.getElementById(`ballPositionRadius-${i}`);
                const positionAngleSlider = document.getElementById(`ballPositionAngle-${i}`);
                const directionSlider = document.getElementById(`ballDirection-${i}`);
                const applyPositionBtn = ballControl.querySelector('.apply-ball-position');
                const applyDirectionBtn = ballControl.querySelector('.apply-ball-direction');
                
                positionRadiusSlider.addEventListener('input', function() {
                    document.getElementById(`ballRadiusValue-${i}`).textContent = this.value;
                });
                
                positionAngleSlider.addEventListener('input', function() {
                    document.getElementById(`ballAngleValue-${i}`).textContent = this.value + '°';
                });
                
                directionSlider.addEventListener('input', function() {
                    document.getElementById(`ballDirectionValue-${i}`).textContent = this.value + '°';
                });
                
                applyPositionBtn.addEventListener('click', function() {
                    const index = parseInt(this.dataset.index);
                    const radius = parseInt(document.getElementById(`ballPositionRadius-${index}`).value);
                    const angle = parseInt(document.getElementById(`ballPositionAngle-${index}`).value) * Math.PI / 180;
                    
                    balls[index].setPositionByPolar(radius, angle);
                    redrawCanvas();
                });
                
                applyDirectionBtn.addEventListener('click', function() {
                    const index = parseInt(this.dataset.index);
                    const angle = parseInt(document.getElementById(`ballDirection-${index}`).value) * Math.PI / 180;
                    
                    balls[index].setDirection(angle);
                });
            }
        }
        
        // 更新小球选择器
        function updateBallSelector() {
            const ballOptions = ballSelector.querySelectorAll('.ball-option');
            ballOptions.forEach((option, index) => {
                if (index === selectedBallIndex) {
                    option.classList.add('active');
                } else {
                    option.classList.remove('active');
                }
            });
        }
        
        // 更新小球控制面板
        function updateBallControls() {
            const ballControls = ballControlsContainer.querySelectorAll('.ball-controls');
            ballControls.forEach((control, index) => {
                if (index === selectedBallIndex) {
                    control.classList.add('active');
                } else {
                    control.classList.remove('active');
                }
            });
        }
        
        // 初始化小球
        function initBalls() {
            balls = [];
            ringCollisions = 0;
            ballCollisions = 0;
            gameOver = false;
            victoryMessage.style.display = 'none';
            
            const ballCount = parseInt(ballCountSlider.value);
            const ballSpeed = parseFloat(ballSpeedSlider.value);
            const ballRadius = parseInt(ballRadiusSlider.value);
            
            // 创建小球
            for (let i = 0; i < ballCount; i++) {
                // 等分分布
                const angleStep = (2 * Math.PI) / ballCount;
                const posAngle = i * angleStep;
                const radius = ringRadius - ballRadius - 20;
                
                const x = centerX + radius * Math.cos(posAngle);
                const y = centerY + radius * Math.sin(posAngle);
                
                // 随机方向
                const directionAngle = Math.random() * 2 * Math.PI;
                
                balls.push(new Ball(
                    x, y, directionAngle, ballSpeed, ballRadius, ballColors[i % ballColors.length], i
                ));
            }
            
            // 创建小球控制面板
            createBallControls();
            updateBallControlsValues();
        }
        
        // 更新小球控制面板的值
        function updateBallControlsValues() {
            for (let i = 0; i < balls.length; i++) {
                const ball = balls[i];
                
                // 计算位置半径和角度
                const dx = ball.x - centerX;
                const dy = ball.y - centerY;
                const radius = Math.sqrt(dx * dx + dy * dy);
                let angle = Math.atan2(dy, dx);
                if (angle < 0) angle += 2 * Math.PI;
                
                // 计算方向角度
                let directionAngle = Math.atan2(ball.vy, ball.vx);
                if (directionAngle < 0) directionAngle += 2 * Math.PI;
                
                // 更新滑块值
                document.getElementById(`ballPositionRadius-${i}`).value = Math.min(radius, ringRadius - 20);
                document.getElementById(`ballPositionAngle-${i}`).value = Math.round(angle * 180 / Math.PI);
                document.getElementById(`ballDirection-${i}`).value = Math.round(directionAngle * 180 / Math.PI);
                
                // 更新显示值
                document.getElementById(`ballRadiusValue-${i}`).textContent = Math.min(radius, ringRadius - 20);
                document.getElementById(`ballAngleValue-${i}`).textContent = Math.round(angle * 180 / Math.PI) + '°';
                document.getElementById(`ballDirectionValue-${i}`).textContent = Math.round(directionAngle * 180 / Math.PI) + '°';
            }
        }
        
        // 绘制圆环
        function drawRing() {
            ctx.beginPath();
            ctx.arc(centerX, centerY, ringRadius, 0, Math.PI * 2);
            ctx.strokeStyle = '#333';
            ctx.lineWidth = 2;
            ctx.stroke();
        }
        
        // 重绘画布
        function redrawCanvas() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            drawRing();
            for (let ball of balls) {
                ball.draw();
            }
        }
        
        // 更新统计信息
        function updateStats() {
            currentTime = (Date.now() - startTime) / 1000;
            timeValue.textContent = currentTime.toFixed(1) + 's';
            
            const activeBalls = balls.filter(ball => ball.isActive);
            remainingBallsValue.textContent = activeBalls.length;
            ringCollisionValue.textContent = ringCollisions;
            ballCollisionValue.textContent = ballCollisions;
            
            let activeSegments = 0;
            for (let ball of balls) {
                for (let segment of ball.activeSegments) {
                    if (segment.active) activeSegments++;
                }
            }
            segmentValue.textContent = activeSegments;
        }
        
        // 动画循环
        function animate() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            
            drawRing();
            
            // 处理小球之间的碰撞
            handleBallCollisions();
            
            // 更新和绘制每个小球
            for (let ball of balls) {
                ball.update();
                
                // 检测线段交叉
                ball.checkSegmentCrossing(balls);
                
                ball.draw();
            }
            
            // 绘制碰撞效果
            drawCollisionEffects();
            
            updateStats();
            
            // 检查胜利条件
            checkVictory();
            
            if (isRunning && !gameOver) {
                animationId = requestAnimationFrame(animate);
            }
        }
        
        // 开始模拟
        function startSimulation() {
            if (!isRunning) {
                isRunning = true;
                gameOver = false;
                if (animationId === null) {
                    startTime = Date.now();
                    animate();
                } else {
                    animationId = requestAnimationFrame(animate);
                }
                startBtn.textContent = '继续模拟';
            }
        }
        
        // 暂停模拟
        function pauseSimulation() {
            isRunning = false;
            if (animationId) {
                cancelAnimationFrame(animationId);
                animationId = null;
            }
        }
        
        // 重置模拟
        function resetSimulation() {
            pauseSimulation();
            collisionEffects = [];
            initBalls();
            startTime = Date.now();
            redrawCanvas();
            updateStats();
        }
        
        // 改变小球方向
        function changeDirections(type) {
            const ballSpeed = parseFloat(ballSpeedSlider.value);
            
            for (let ball of balls) {
                if (!ball.isActive) continue;
                
                let newAngle;
                
                if (type === 'random') {
                    newAngle = Math.random() * 2 * Math.PI;
                } else if (type === 'center') {
                    newAngle = Math.atan2(centerY - ball.y, centerX - ball.x);
                } else {
                    const tangentAngle = Math.atan2(ball.y - centerY, ball.x - centerX) + Math.PI/2;
                    newAngle = tangentAngle + (Math.random() - 0.5) * Math.PI/4;
                }
                
                ball.vx = Math.cos(newAngle) * ballSpeed;
                ball.vy = Math.sin(newAngle) * ballSpeed;
                ball.initialAngle = newAngle;
            }
            
            updateBallControlsValues();
        }
        
        // 改变小球位置
        function changePositions(type) {
            const ballRadius = parseInt(ballRadiusSlider.value);
            
            for (let i = 0; i < balls.length; i++) {
                const ball = balls[i];
                let x, y;
                
                if (type === 'even') {
                    // 等分分布
                    const angleStep = (2 * Math.PI) / balls.length;
                    const posAngle = i * angleStep;
                    const radius = ringRadius - ballRadius - 20;
                    x = centerX + radius * Math.cos(posAngle);
                    y = centerY + radius * Math.sin(posAngle);
                } else if (type === 'random') {
                    // 随机分布
                    const randomAngle = Math.random() * 2 * Math.PI;
                    const randomRadius = (Math.random() * 0.7 + 0.3) * (ringRadius - ballRadius - 20);
                    x = centerX + randomRadius * Math.cos(randomAngle);
                    y = centerY + randomRadius * Math.sin(randomAngle);
                } else {
                    // 圆形分布
                    const circleRadius = ringRadius * 0.5;
                    const angleStep = (2 * Math.PI) / balls.length;
                    const posAngle = i * angleStep;
                    x = centerX + circleRadius * Math.cos(posAngle);
                    y = centerY + circleRadius * Math.sin(posAngle);
                }
                
                ball.x = x;
                ball.y = y;
            }
            
            updateBallControlsValues();
            redrawCanvas();
        }
        
        // 事件监听
        startBtn.addEventListener('click', startSimulation);
        pauseBtn.addEventListener('click', pauseSimulation);
        resetBtn.addEventListener('click', resetSimulation);
        
        // 位置按钮事件
        positionEvenBtn.addEventListener('click', function() {
            changePositions('even');
        });
        
        positionRandomBtn.addEventListener('click', function() {
            changePositions('random');
        });
        
        positionCircleBtn.addEventListener('click', function() {
            changePositions('circle');
        });
        
        // 方向按钮事件
        directionRandomBtn.addEventListener('click', function() {
            changeDirections('random');
        });
        
        directionCenterBtn.addEventListener('click', function() {
            changeDirections('center');
        });
        
        directionTangentBtn.addEventListener('click', function() {
            changeDirections('tangent');
        });
        
        // 滑块事件
        ballCountSlider.addEventListener('input', function() {
            ballCountValue.textContent = this.value;
            resetSimulation();
        });
        
        ballSpeedSlider.addEventListener('input', function() {
            ballSpeedValue.textContent = this.value;
            // 更新所有小球的速度
            const speed = parseFloat(this.value);
            for (let ball of balls) {
                if (!ball.isActive) continue;
                
                const currentSpeed = Math.sqrt(ball.vx * ball.vx + ball.vy * ball.vy);
                ball.vx = (ball.vx / currentSpeed) * speed;
                ball.vy = (ball.vy / currentSpeed) * speed;
                ball.initialSpeed = speed;
            }
        });
        
        ballRadiusSlider.addEventListener('input', function() {
            ballRadiusValue.textContent = this.value;
            resetSimulation();
        });
        
        // 初始化
        initBalls();
        redrawCanvas();
        updateStats();
    </script>
</body>
</html>